home *** CD-ROM | disk | FTP | other *** search
/ Mac Power 1997 December / MACPOWER-1997-12.ISO.7z / MACPOWER-1997-12.ISO / AMUG / PROGRAMMING / Raven 1.2.sit / Raven 1.2 / Source / Foundation / Common / ZMemoryHeap.cpp < prev    next >
Text File  |  1997-09-04  |  20KB  |  847 lines

  1. /*
  2.  *  File:       ZMemoryHeap.cpp
  3.  *  Summary:    A class that uses a TAllocator and zero or more TFixedAllocators
  4.  *                to allocate blocks of memory.
  5.  *  Written by: Jesse Jones
  6.  *
  7.  *  Copyright ゥ 1997 Jesse Jones. 
  8.  *    For conditions of distribution and use, see copyright notice in ZTypes.h  
  9.  *
  10.  *  Change History (most recent first):    
  11.  *
  12.  *         <7>     8/15/97    JDJ        Block count functions are defined if !RELEASE (instead
  13.  *                                    of if DEBUG).
  14.  *         <6>     5/02/97    JDJ        Fixed an ASSERT in AddAllocator.
  15.  *         <5>     4/13/97    JDJ        Includes Gestalt.h
  16.  *         <4>     3/05/97    JDJ        Rewrote FSSpecOpen.
  17.  *         <3>     2/28/97    JDJ        DumpLeaks tells people to turn off virtual memory.
  18.  *         <2>     2/25/97    JDJ        Deallocate validates the block before zapping it.
  19.  *         <1>     1/29/97    JDJ        Created
  20.  */
  21.  
  22. #include <ZMemoryHeap.h>
  23.  
  24. #include <Errors.h>
  25. #include <Gestalt.h>
  26. #include <Limits.h>
  27. #include <Processes.h>
  28. #include <Stdio.h>
  29. #include <TextUtils.h>
  30.  
  31. #include <ZAllocator.h>
  32. #include <ZDebug.h>
  33. #include <ZExceptions.h>
  34. #include <ZFixedAllocator.h>
  35. #include <ZMemUtils.h>
  36. #include <ZStackCrawl.h>
  37. #include <ZStringUtils.h>
  38.  
  39. #if !RELEASE
  40. #include <ZDialogUtils.h>
  41. #endif
  42.  
  43.  
  44. //-----------------------------------
  45. //    Constants
  46. //
  47. const long kStackDepth = 8;                    // use an even number to keep data aligned on an 8-byte boundary
  48.  
  49. const long kDebugHeaderLen  = kStackDepth*sizeof(StackFrameID) + 2*sizeof(long);
  50. const long kDebugTrailerLen = sizeof(long);
  51. const long kDebugOverhead   = kDebugHeaderLen + kDebugTrailerLen;
  52.  
  53.  
  54. // ===================================================================================
  55. //    struct SMemoryBlock
  56. // ===================================================================================
  57. #if DEBUG
  58.     struct SMemoryBlock {
  59.         StackFrameID    crawl[kStackDepth];    // stack crawl (first is nil if no stack crawl)
  60.         ulong            bytes;                // exact size of user data
  61.         long            marker;                // 0xF1F1F1F1
  62.         
  63.         Byte            data[4];            // variable length data
  64. //        Byte            marker2;            // four or more 0xF2 bytes
  65.     };
  66. #else
  67.     struct SMemoryBlock {
  68.         Byte    data[4];                    // variable length data
  69.     };
  70. #endif
  71.  
  72.  
  73. // ===================================================================================
  74. //    Internal Functions
  75. // ===================================================================================
  76.  
  77. //---------------------------------------------------------------
  78. //
  79. // GetBlock (void*)
  80. //
  81. //---------------------------------------------------------------
  82. inline SMemoryBlock* GetBlock(void* ptr)
  83. {
  84. #if DEBUG
  85.     SMemoryBlock* block = reinterpret_cast<SMemoryBlock*>((char*) ptr - kDebugHeaderLen);
  86. #else
  87.     SMemoryBlock* block = reinterpret_cast<SMemoryBlock*>(ptr);
  88. #endif
  89.  
  90.     return block;
  91. }
  92.  
  93.  
  94. //---------------------------------------------------------------
  95. //
  96. // GetBlock (const void*)
  97. //
  98. //---------------------------------------------------------------
  99. inline const SMemoryBlock* GetBlock(const void* ptr)
  100. {
  101. #if DEBUG
  102.     const SMemoryBlock* block = reinterpret_cast<const SMemoryBlock*>((char*) ptr - kDebugHeaderLen);
  103. #else
  104.     const SMemoryBlock* block = reinterpret_cast<const SMemoryBlock*>(ptr);
  105. #endif
  106.  
  107.     return block;
  108. }
  109.  
  110.  
  111. //---------------------------------------------------------------
  112. //
  113. // VirtualMemIsOn
  114. //
  115. //---------------------------------------------------------------
  116. static bool VirtualMemIsOn()
  117. {    
  118.     long result;
  119.     
  120.     bool on = Gestalt(gestaltVMAttr, &result) == noErr && (result & 1) == 1;
  121.     
  122.     return on;
  123. }
  124.  
  125.  
  126. //---------------------------------------------------------------
  127. //
  128. // FSSpecOpen
  129. //
  130. //---------------------------------------------------------------
  131. #if DEBUG
  132. static FILE* FSSpecOpen(const FSSpec& spec, const char* mode)
  133. {
  134.     FILE* file = nil;
  135.  
  136.     short oldVolume;
  137.     long oldDir;
  138.     OSErr err = HGetVol(nil, &oldVolume, &oldDir);
  139.     if (err == noErr) {
  140.  
  141.         err = HSetVol(0, spec.vRefNum, spec.parID);
  142.         if (err == noErr) {
  143.             char fName[256];
  144.  
  145.             ulong len = spec.name[0];
  146.             BlockMoveData(spec.name + 1, fName, len);
  147.             fName[len] = '¥0';
  148.  
  149.             file = fopen(fName, mode);
  150.         }
  151.  
  152.         HSetVol(nil, oldVolume, oldDir);
  153.     }
  154.  
  155.     return file;
  156. }
  157. #endif
  158.  
  159.  
  160. //---------------------------------------------------------------
  161. //
  162. // ValidateBlock
  163. //
  164. //---------------------------------------------------------------
  165. #if DEBUG
  166. static void ValidateBlock(const void* ptr, long size, void* refCon)
  167. {
  168.     #pragma unused(refCon)
  169.     
  170.     const SMemoryBlock* block = reinterpret_cast<const SMemoryBlock*>(ptr);
  171.  
  172.     ASSERT(block != nil);
  173.             
  174.     if (block->crawl[0] == nil)
  175.         for (ulong index = 1; index < kStackDepth; index++)
  176.             ASSERT(block->crawl[index] == nil);
  177.  
  178.     ASSERT(block->bytes <= size - kDebugOverhead);
  179.     ASSERT(block->marker == 0xF1F1F1F1);
  180.  
  181.     Byte* trailer = reinterpret_cast<Byte*>((char*) block + kDebugHeaderLen + block->bytes);
  182.     Byte* end     = reinterpret_cast<Byte*>((char*) block + size);
  183.     ASSERT(trailer < end);
  184.  
  185.     while (trailer < end)
  186.         ASSERT(*trailer++ == 0xF2);
  187. }
  188. #endif
  189.  
  190.  
  191. //---------------------------------------------------------------
  192. //
  193. // DumpLeaks
  194. //
  195. //---------------------------------------------------------------
  196. #if DEBUG
  197. static void DumpLeaks(const void* ptr, long size, void* refCon)
  198. {    
  199.     ASSERT(refCon != nil);
  200.     
  201.     ValidateBlock(ptr, (long) size, refCon);
  202.     
  203.     const SMemoryBlock* block = reinterpret_cast<const SMemoryBlock*>(ptr);
  204.     
  205.     FILE* file = reinterpret_cast<FILE*>(refCon);
  206.     
  207.     if (block->crawl[0] != nil) {
  208.         fprintf(file, "Block size = %d¥n", block->bytes);
  209.         
  210.         for (ulong index = kStackDepth - 1; index != ULONG_MAX; index--) {
  211.             StackFrameID id = block->crawl[index];
  212.             if (id != nil) {                                    // stack may be smaller than kStackDepth
  213.                 SStackFrame frame = TStackCrawl::GetFrame(id);
  214.             
  215.                 fprintf(file, "%s + 0x%lX¥n", frame.name.c_str(), frame.offset);
  216.             }
  217.         }
  218.         fprintf(file, "¥n");
  219.     }
  220. }
  221. #endif
  222.  
  223. #pragma mark -
  224.  
  225. // ===================================================================================
  226. //    class TMemoryHeap
  227. // ===================================================================================
  228.  
  229. //---------------------------------------------------------------
  230. //
  231. // TMemoryHeap::~TMemoryHeap
  232. //
  233. //---------------------------------------------------------------
  234. TMemoryHeap::~TMemoryHeap()
  235. {
  236.     for (ulong index = 0; index < 256; index++)
  237.         delete mFixedAllocators[index];
  238.         
  239.     delete mAllocator;
  240. }
  241.  
  242.  
  243. //---------------------------------------------------------------
  244. //
  245. // TMemoryHeap::TMemoryHeap
  246. //
  247. //---------------------------------------------------------------
  248. TMemoryHeap::TMemoryHeap(TAllocator* takeAllocator)
  249. {
  250.     ASSERT(takeAllocator != nil);
  251.     ASSERT(kDebugOverhead % 4 == 0);        // so fixed allocator sizes stay on 4-byte boundaries
  252.     ASSERT(kDebugOverhead == sizeof(SMemoryBlock));
  253.     ASSERT(offsetof(SMemoryBlock, data) == kDebugHeaderLen);
  254.     ASSERT(offsetof(SMemoryBlock, data) % 8 == 0);
  255.     
  256.     mAllocator = takeAllocator;
  257.  
  258.     mBlockCount    = 0;
  259.     mLeakCount     = 0;
  260.     mHighwater     = 0;
  261.     mCurrentBytes  = 0;
  262.     mDebugOverhead = 0;
  263.         
  264.     for (ulong index = 0; index < 256; index++)
  265.         mFixedAllocators[index] = nil;
  266.  
  267. #if DEBUG
  268.     mZap           = true;
  269.     mLeakChecking  = 1;    
  270. #endif
  271.     
  272. #if !RELEASE
  273.     for (ulong index = 0; index < 256; index++) {
  274.         mTotalBlockCounts[index]   = 0;
  275.         mCurrentBlockCounts[index] = 0;
  276.     }
  277. #endif
  278. }
  279.  
  280.  
  281. //---------------------------------------------------------------
  282. //
  283. // TMemoryHeap::AddAllocator
  284. //
  285. //---------------------------------------------------------------
  286. void TMemoryHeap::AddAllocator(ulong size, ulong maxBlocks)
  287. {
  288.     ASSERT(size > 0);
  289.     ASSERT(size < 256);
  290.     ASSERT(size % 4 == 0);
  291.     ASSERT(maxBlocks > 0);
  292.     
  293. #if DEBUG
  294.     size += kDebugOverhead;
  295.  
  296.     ASSERT(mFixedAllocators[size] == nil);
  297.  
  298.     long temp = mLeakChecking;
  299.     
  300.     try {
  301.         mLeakChecking = 0;
  302.         ASSERT(!this->IsLeakChecking());
  303.         
  304.         if (size < 256)
  305.             mFixedAllocators[size] = new TFixedAllocator(size, maxBlocks);
  306.     
  307.         mLeakChecking = temp;
  308.  
  309.     } catch (...) {
  310.         mLeakChecking = temp;
  311.         throw;
  312.     }
  313.     
  314. #else    
  315.     if (size < 256)
  316.         mFixedAllocators[size] = new TFixedAllocator(size, maxBlocks);
  317. #endif
  318. }
  319.  
  320.  
  321. //---------------------------------------------------------------
  322. //
  323. // TMemoryHeap::GetAllocator
  324. //
  325. //---------------------------------------------------------------
  326. const TFixedAllocator* TMemoryHeap::GetAllocator(ulong size) const
  327. {
  328.     ASSERT(size < 256); 
  329.     
  330.     const TFixedAllocator* alloc = nil;
  331.     
  332. #if DEBUG
  333.     size += kDebugOverhead;
  334. #endif
  335.     
  336.     if (size < 256)
  337.         alloc = mFixedAllocators[size];
  338.  
  339.     return alloc;
  340. }
  341.  
  342.  
  343. //---------------------------------------------------------------
  344. //
  345. // TMemoryHeap::GetTotalBlockCount
  346. //
  347. //---------------------------------------------------------------
  348. #if !RELEASE
  349. ulong TMemoryHeap::GetTotalBlockCount(ulong size) const
  350. {
  351.     ASSERT(size < 256); 
  352.     
  353.     ulong count = 0;
  354.  
  355. #if DEBUG
  356.     size += kDebugOverhead;
  357. #endif
  358.  
  359.     if (size < 256)
  360.         count = mTotalBlockCounts[size];
  361.     
  362.     return count;
  363. }
  364. #endif
  365.  
  366.  
  367. //---------------------------------------------------------------
  368. //
  369. // TMemoryHeap::GetCurrentBlockCount
  370. //
  371. //---------------------------------------------------------------
  372. #if !RELEASE
  373. ulong TMemoryHeap::GetCurrentBlockCount(ulong size) const
  374. {
  375.     ASSERT(size < 256); 
  376.     
  377.     ulong count = 0;
  378.     
  379. #if DEBUG
  380.     size += kDebugOverhead;
  381. #endif
  382.  
  383.     if (size < 256)
  384.         count = mCurrentBlockCounts[size];
  385.     
  386.     return count;
  387. }
  388. #endif
  389.  
  390.  
  391. //---------------------------------------------------------------
  392. //
  393. // TMemoryHeap::DumpCommonBlocks
  394. //
  395. //---------------------------------------------------------------
  396. #if !RELEASE
  397. struct SBlockCount {
  398.     ulong    size;
  399.     ulong    current;
  400.     ulong    total;
  401.     
  402.     bool operator==(const SBlockCount& rhs) const    {return total == rhs.total;}
  403.     bool operator<(const SBlockCount& rhs) const    {return total < rhs.total;}
  404. };
  405.  
  406. #if !SGI_STL
  407. __MSL_FIX_ITERATORS__(SBlockCount);
  408. #endif
  409.  
  410. void TMemoryHeap::DumpCommonBlocks()
  411. {
  412.     char buffer[4096];
  413.     long offset = 0;
  414.     
  415.     offset += sprintf(buffer + offset, "Bytes   Current    Total¥r");
  416.  
  417.     SBlockCount blocks[256];
  418.     for (ulong index = 0; index < 256; index++) {
  419.         blocks[index].size    = index;
  420.         blocks[index].current = this->GetCurrentBlockCount(index);
  421.         blocks[index].total   = this->GetTotalBlockCount(index);
  422.     }
  423.         
  424.     sort(blocks, blocks + 256);
  425.  
  426.     for (long index = 255; index >= 255 - 3; index--)
  427.         offset += sprintf(buffer + offset, "  %3d   %7d  %7d¥r", blocks[index].size, blocks[index].current, blocks[index].total);
  428.     
  429.     DoStop("Number of blocks allocated for sizes under 256", buffer);
  430. }
  431. #endif
  432.  
  433.  
  434. //---------------------------------------------------------------
  435. //
  436. // TMemoryHeap::DumpAllocatorCapacities
  437. //
  438. //---------------------------------------------------------------
  439. #if !RELEASE
  440. void TMemoryHeap::DumpAllocatorCapacities()
  441. {
  442.     char buffer[4096];
  443.     long offset = 0;
  444.     
  445.     offset += sprintf(buffer + offset, "Bytes  Current    Max¥r");
  446.     for (ulong size = 1; size < 256; size++) {
  447.         const TFixedAllocator* alloc = this->GetAllocator(size);
  448.         if (alloc != nil) 
  449.             offset += sprintf(buffer + offset, "  %3d    %4d%%  %4d%%¥r", size, alloc->GetCurrentPercent(), alloc->GetMaxPercent());
  450.     }        
  451.         
  452.     DoStop("Fixed allocator capacities", buffer);
  453. }
  454. #endif
  455.  
  456.  
  457. //---------------------------------------------------------------
  458. //
  459. // TMemoryHeap::Allocate
  460. //
  461. //---------------------------------------------------------------
  462. void* TMemoryHeap::Allocate(ulong actualBytes)
  463. {
  464.     ASSERT(actualBytes < 16*1024L*1024L);
  465.     
  466.     SMemoryBlock* block = nil;
  467.     
  468.     ulong bytes = (actualBytes + 3) & ~3;    // round bytes up to next 4-byte boundary
  469. #if DEBUG
  470.     bytes += kDebugOverhead;
  471. #endif
  472.  
  473.     if (bytes < 256 && mFixedAllocators[bytes] != nil)
  474.         block = reinterpret_cast<SMemoryBlock*>(mFixedAllocators[bytes]->Allocate());
  475.     
  476.     if (block == nil)
  477.         block = reinterpret_cast<SMemoryBlock*>(mAllocator->Allocate(bytes));
  478.             
  479.     if (block != nil) {
  480.         mBlockCount++;
  481.         ulong size = this->GetTotalBlockSize(block->data);
  482.         mCurrentBytes += size;
  483.  
  484. #if DEBUG
  485.         this->AddDebugInfo(block, actualBytes, this->GetBlockSize(block->data) + kDebugOverhead);    // bytes may be off by a few
  486.         
  487.         if (this->IsLeakChecked(block->data))
  488.             mLeakCount++;
  489.             
  490.         mDebugOverhead += kDebugOverhead;        
  491.                 
  492. #if !__profile__
  493.         if (mZap)
  494.             SetMemory(block->data, kNewFill, block->bytes);
  495. #endif
  496. #endif
  497.         
  498. #if !RELEASE
  499.         if (bytes < 256) {
  500.             mTotalBlockCounts[bytes]   += 1;
  501.             mCurrentBlockCounts[bytes] += 1;
  502.         }
  503. #endif
  504.  
  505.         if (mCurrentBytes > mHighwater)
  506.             mHighwater = mCurrentBytes;
  507.     }
  508.         
  509.     return block != nil ? block->data : nil;
  510. }
  511.  
  512.  
  513. //---------------------------------------------------------------
  514. //
  515. // TMemoryHeap::Deallocate
  516. //
  517. //---------------------------------------------------------------
  518. void TMemoryHeap::Deallocate(void* ptr)
  519. {
  520.     if (ptr != nil) {
  521.         SMemoryBlock* block = GetBlock(ptr);
  522.  
  523.         ulong bytes = this->GetBlockSize(block->data);
  524.  
  525. #if DEBUG        
  526.         mDebugOverhead -= kDebugOverhead;
  527.  
  528.         if (this->IsLeakChecked(block->data))
  529.             mLeakCount--;
  530.             
  531. #if !__profile__
  532.         this->ValidateBlock(block->data);
  533.  
  534.         if (mZap)
  535.             SetMemory(block->data, kFreeFill, block->bytes);
  536. #endif
  537.  
  538.         bytes += kDebugOverhead;
  539. #endif
  540.  
  541. #if DEBUG
  542.         // Allocated bytes may be slightly larger than requested bytes.
  543.         ulong requestedBytes = ((block->bytes + 3) & ~3) + kDebugOverhead;
  544.         if (requestedBytes < 256)
  545.             mCurrentBlockCounts[requestedBytes] -= 1;
  546. #endif
  547.  
  548.         mBlockCount--;
  549.         ulong size = this->GetTotalBlockSize(block->data);
  550.         
  551.         if (bytes < 256 && mFixedAllocators[bytes] != nil && mFixedAllocators[bytes]->HasBlock(block))
  552.             mFixedAllocators[bytes]->Deallocate(block);
  553.         else
  554.             mAllocator->Deallocate(block);
  555.  
  556.         mCurrentBytes -= size;
  557.     }
  558. }
  559.  
  560.  
  561. //---------------------------------------------------------------
  562. //
  563. // TMemoryHeap::GetHeapSize
  564. //
  565. //---------------------------------------------------------------
  566. ulong TMemoryHeap::GetHeapSize() const
  567. {
  568.     ulong size = mAllocator->GetHeapSize();
  569.     
  570.     for (ulong index = 4; index < 256; index += 4)
  571.         if (mFixedAllocators[index] != nil)
  572.             size += mFixedAllocators[index]->GetHeapSize();
  573.     
  574.     return size;
  575. }
  576.  
  577.  
  578. //---------------------------------------------------------------
  579. //
  580. // TMemoryHeap::GetPoolCount
  581. //
  582. //---------------------------------------------------------------
  583. ulong TMemoryHeap::GetPoolCount() const
  584. {
  585.     ulong count = mAllocator->GetPoolCount();
  586.     
  587.     return count;
  588. }
  589.  
  590.  
  591. //---------------------------------------------------------------
  592. //
  593. // TMemoryHeap::GetBlockSize
  594. //
  595. //---------------------------------------------------------------
  596. ulong TMemoryHeap::GetBlockSize(const void* ptr) const
  597. {
  598.     ASSERT(ptr != nil);
  599.     
  600.     ulong size = 0;
  601.     
  602.     const SMemoryBlock* block = GetBlock(ptr);
  603.  
  604.     for (ulong bytes = 4; bytes < 256 && size == 0; bytes += 4) {    // should be fast since there should only be a few fixed allocators
  605.         if (mFixedAllocators[bytes] != nil && mFixedAllocators[bytes]->HasBlock(block))
  606.             size = bytes;
  607.     }
  608.  
  609.     if (size == 0)
  610.         size = mAllocator->GetBlockSize(block);
  611.  
  612. #if DEBUG
  613.     size -= kDebugOverhead;
  614. #endif
  615.  
  616.     return size;
  617. }
  618.  
  619.  
  620. //---------------------------------------------------------------
  621. //
  622. // TMemoryHeap::GetTotalBlockSize
  623. //
  624. //---------------------------------------------------------------
  625. ulong TMemoryHeap::GetTotalBlockSize(const void* ptr) const
  626. {
  627.     ASSERT(ptr != nil);
  628.     
  629.     ulong size = 0;
  630.     
  631.     const SMemoryBlock* block = GetBlock(ptr);
  632.  
  633.     for (ulong bytes = 4; bytes < 256 && size == 0; bytes += 4) {
  634.         if (mFixedAllocators[bytes] != nil && mFixedAllocators[bytes]->HasBlock(block))
  635.             size = bytes;
  636.     }
  637.  
  638.     if (size == 0)
  639.         size = mAllocator->GetTotalBlockSize(block);
  640.  
  641.     return size;
  642. }
  643.  
  644.  
  645. //---------------------------------------------------------------
  646. //
  647. // TMemoryHeap::ValidateBlock
  648. //
  649. //---------------------------------------------------------------
  650. #if DEBUG
  651. void TMemoryHeap::ValidateBlock(const void* ptr) const
  652. {
  653.     ASSERT(ptr != nil);
  654.             
  655.     const SMemoryBlock* block = GetBlock(ptr);
  656.  
  657.     ulong size = 0;
  658.  
  659.     for (ulong bytes = 4; bytes < 256 && size == 0; bytes += 4)
  660.         if (mFixedAllocators[bytes] != nil && mFixedAllocators[bytes]->HasBlock(block))
  661.             size = bytes;
  662.  
  663.     if (size == 0) {
  664.         mAllocator->ValidateBlock(block);
  665.  
  666.         size = mAllocator->GetBlockSize(block);
  667.     }
  668.     
  669.     ::ValidateBlock(block, (long) size, nil);
  670. }
  671. #endif
  672.  
  673.  
  674. //---------------------------------------------------------------
  675. //
  676. // TMemoryHeap::ValidateHeap
  677. //
  678. //---------------------------------------------------------------
  679. #if DEBUG
  680. void TMemoryHeap::ValidateHeap() const
  681. {
  682.     for (ulong bytes = 4; bytes < 256; bytes += 4)
  683.         if (mFixedAllocators[bytes] != nil)
  684.             mFixedAllocators[bytes]->ValidateHeap(::ValidateBlock);
  685.  
  686.     mAllocator->ValidateHeap(::ValidateBlock);
  687. }
  688. #endif
  689.  
  690.  
  691. //---------------------------------------------------------------
  692. //
  693. // TMemoryHeap::IsLeakChecked
  694. //
  695. //---------------------------------------------------------------
  696. #if DEBUG
  697. bool TMemoryHeap::IsLeakChecked(const void* ptr) const
  698. {
  699.     ASSERT(ptr != nil);
  700.         
  701.     const SMemoryBlock* block = GetBlock(ptr);
  702.  
  703.     return block->crawl[0] != nil;
  704. }
  705. #endif
  706.  
  707.  
  708. //---------------------------------------------------------------
  709. //
  710. // TMemoryHeap::AddDebugInfo
  711. //
  712. //---------------------------------------------------------------
  713. #if DEBUG
  714. void TMemoryHeap::AddDebugInfo(SMemoryBlock* block, ulong actualBytes, ulong size)
  715. {
  716.     ASSERT(block != nil);
  717.     ASSERT(size >= sizeof(SMemoryBlock));
  718.         
  719.     block->bytes  = actualBytes;
  720.     block->marker = 0xF1F1F1F1;
  721.     
  722.     ulong index;
  723.     for (index = 0; index < kStackDepth; index++)
  724.         block->crawl[index] = nil;
  725.  
  726.     Byte* trailer = reinterpret_cast<Byte*>((char*) block + kDebugHeaderLen + actualBytes);
  727.     Byte* end     = reinterpret_cast<Byte*>((char*) block + size);
  728.  
  729.     while (trailer < end)
  730.         *trailer++ = 0xF2;
  731.         
  732. #if !__profile__
  733.     if (this->IsLeakChecking()) {
  734.         TStackCrawl crawl(4, kStackDepth);
  735.     
  736.         ulong count = crawl.GetNumFrames();            // stack depth may be smaller than kStackDepth
  737.         for (index = 0; index < count; index++)
  738.             block->crawl[index] = crawl.GetID(index);        
  739.     }
  740. #endif
  741. }
  742. #endif
  743.  
  744.  
  745. //---------------------------------------------------------------
  746. //
  747. // TMemoryHeap::GetLeaksLog
  748. //
  749. //---------------------------------------------------------------
  750. #if DEBUG
  751. FSSpec TMemoryHeap::GetLeaksLog() const
  752. {
  753.     FSSpec spec;
  754.  
  755.     ProcessSerialNumber psn;
  756.     OSErr err = GetCurrentProcess(&psn);
  757.     ThrowIfOSErr(err);
  758.     
  759.     ProcessInfoRec info;        
  760.     info.processInfoLength = sizeof(info);
  761.     info.processName       = 0;
  762.     info.processAppSpec    = &spec;
  763.     err = GetProcessInformation(&psn, &info);
  764.     ThrowIfOSErr(err);
  765.     
  766.     unsigned char* name = "¥pleaks.log";
  767.     BlockMoveData(name, spec.name, name[0] + 1UL);
  768.     
  769.     return spec;
  770. }
  771. #endif
  772.  
  773.  
  774. //---------------------------------------------------------------
  775. //
  776. // TMemoryHeap::DumpLeaks
  777. //
  778. //---------------------------------------------------------------
  779. #if DEBUG
  780. void TMemoryHeap::DumpLeaks() const
  781. {
  782.     FILE* file = nil;    
  783.  
  784.     try {
  785.         FSSpec spec = this->GetLeaksLog();
  786.  
  787.         file = FSSpecOpen(spec, "w");    
  788.         if (file == nil)
  789.             ThrowOSErr(openErr);
  790.             
  791.         if (mLeakCount == 0)
  792.             fprintf(file, "No memory leaks.¥n");
  793.             
  794.         else {
  795.             if (VirtualMemIsOn())                    // ・・・ハStack crawl code doesn't work quite right with virtual memory
  796.                 fprintf(file, "Turn off virtual memory to see the symbol names in the stack crawl.¥n¥n");
  797.  
  798.             if (mLeakCount == 1)
  799.                 fprintf(file, "You have one leak:¥n¥n");
  800.             else
  801.                 fprintf(file, "You have %d leaks:¥n¥n", mLeakCount);
  802.  
  803.             for (ulong bytes = 4; bytes < 256; bytes += 4)
  804.                 if (mFixedAllocators[bytes] != nil)
  805.                     mFixedAllocators[bytes]->ValidateHeap(::DumpLeaks, file);
  806.  
  807.             mAllocator->ValidateHeap(::DumpLeaks, file);
  808.         }
  809.         
  810.     } catch (const TSystemException& e) {
  811.         DEBUGSTR("Couldn't dump the leaks.log because of an %d error", e.mError);
  812.  
  813.     } catch (...) {
  814.         DEBUGSTR("Couldn't dump the leaks.log because of an unknown error");
  815.     }        
  816.  
  817.     fclose(file);
  818. }
  819. #endif
  820.  
  821.  
  822. //---------------------------------------------------------------
  823. //
  824. // TMemoryHeap::operator new                            [static]
  825. //
  826. //---------------------------------------------------------------
  827. void* TMemoryHeap::operator new(size_t size)
  828. {
  829.     void* ptr = NewPtr(size);
  830.     ThrowIfNil(ptr);
  831.     
  832.     return ptr;
  833. }
  834.  
  835.  
  836. //---------------------------------------------------------------
  837. //
  838. // TMemoryHeap::operator delete                            [static]
  839. //
  840. //---------------------------------------------------------------
  841. void TMemoryHeap::operator delete(void* ptr)
  842. {
  843.     if (ptr != nil)
  844.         DisposePtr((Ptr) ptr);
  845. }
  846.  
  847.